package com.lhz.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Created by Vi
 * Date on 2019/4/25 18:16
 */
@Configuration
public class RedisTemplateConfig {
    @Bean("redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();

        // 设置连接工厂
        template.setConnectionFactory(connectionFactory);

        // 设置序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //key序列化
        template.setKeySerializer(stringRedisSerializer);
        //value序列化
        template.setValueSerializer(getJackson2JsonRedisSerializer());
        //Hash key序列化
        template.setHashKeySerializer(stringRedisSerializer);
        //Hash value序列化
        template.setHashValueSerializer(getJackson2JsonRedisSerializer());

        template.afterPropertiesSet();

        return template;
    }


    //缓存管理器
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();

        // 设置缓存管理器管理
        defaultCacheConfig = defaultCacheConfig
                // 缓存的默认过期时间:
                .entryTtl(Duration.ofSeconds(36000))
                // 设置 key为string序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                // 设置value为json序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(getJackson2JsonRedisSerializer()))
                // 不缓存空值
                .disableCachingNullValues();
        Set<String> cacheNames = new HashSet<>();
        // cacheNames.add("testCacheName1");
        // cacheNames.add("testCacheName2");

        // 对每个缓存空间应用不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        // configMap.put("testCacheName1", defaultCacheConfig.entryTtl(Duration.ofSeconds(1000)));
        // configMap.put("testCacheName2", defaultCacheConfig.entryTtl(Duration.ofSeconds(5000)));

        return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(defaultCacheConfig).initialCacheNames(cacheNames).withInitialCacheConfigurations(configMap).build();
    }

    /**
     * 获取Jackson2JsonRedisSerializer序列化对象
     *
     * @return o
     */
    private Jackson2JsonRedisSerializer<Object> getJackson2JsonRedisSerializer() {

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型，类必须是非final修饰的，final修饰的类，比如String,Integer等会跑出异常
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        // JSON序列化配置
        return new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
    }

}
